package org.lyu.util;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * 工具类
 * 常用的JDBC代码整理到这里
 * @author Administrator
 *
 */
public class MyDbUtils1 {
	
	private static String url = "jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true";
	private static String name = "root";
	private static String pwd = "123456";
	
	/**
	 * 静态代码块，和静态变量一样。
	 * 会在DbUtils第一次调用的时候，执行一遍。
	 */
	static {
		// 加载驱动，类加载机制
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * 获取链接
	 * @return 链接 or null
	 */
	public static Connection getConnection() {
		try {
			return DriverManager.getConnection(url, name, pwd);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 释放资源
	 * @param rSet
	 * @param statement
	 * @param conn
	 */
	public static void close(Statement statement, Connection conn) {
		
		try {
			if (statement != null) {
				statement.close();
			}
		} catch (Exception e) {
		}
		
		try {
			if (conn != null) {
				conn.close();
			}
		} catch (Exception e) {
		}
	}
	
	/**
	 * 释放资源
	 * @param rSet
	 * @param statement
	 * @param conn
	 */
	public static void close(ResultSet rSet, Statement statement, Connection conn) {
		//释放资源
		try {
			if (rSet != null) {
				rSet.close();
			}
		} catch (Exception e) {
		}
		
		try {
			if (statement != null) {
				statement.close();
			}
		} catch (Exception e) {
		}
		
		try {
			if (conn != null) {
				conn.close();
			}
		} catch (Exception e) {
		}
	}
	
	/**
	 * orm Object Relation Mapping 对象关系映射
	 * 
	 * 使用反射查询所有的宠物
	 * 
	 * @param <T> 声明 T是个泛型类型
	 * @param clazz T.class
	 * @param sql sql语句 
	 * @return List or Empty List
	 */
	public static <T> List<T> excuteQueryForList(Class<T> clazz, String sql) {

		List<T> result = new ArrayList<T>();

		Connection connection = null;
		Statement statement = null;
		ResultSet rs = null;

		try {

			connection = MyDbUtils1.getConnection();

			statement = connection.createStatement();

			rs = statement.executeQuery(sql);

			// 元数据 Meta 元 （元认知、元学习）
			ResultSetMetaData rsmd = rs.getMetaData();

			// 6.1通过ResultSetMetaData得到columnCount,columnLabel；通过ResultSet得到列值
			int columnCount = rsmd.getColumnCount();

			while (rs.next()) {

				T t = clazz.getDeclaredConstructor().newInstance();
				for (int i = 0; i < columnCount; i++) {
					// 获取列的别名: 列的别名，使⽤类的属性名充当
					String columnLabel = rsmd.getColumnLabel(i + 1);

					// 列值
					Object columnValue = rs.getObject(columnLabel);

					// 使用反射，给对象的相应属性赋值
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columnValue);
				}

				result.add(t);

			}

		} catch (Exception e) {
			// TODO: handle exception
		} finally {
			MyDbUtils1.close(rs, statement, connection);
		}

		return result;

	}
	
	/**
	 * 查询所有使用PreparedStatement
	 * @param <T> 声明 T是个泛型类型
	 * @param clazz T.class
	 * @param sql sql语句
	 * @param args 参数
	 * @return List or Empty List
	 */
	public static <T> List<T> excuteQueryForList(Class<T> clazz,String sql, Object... args) {

		List<T> result = new ArrayList<T>();

		Connection connection = null;
		PreparedStatement statement = null;
		ResultSet rs = null;

		try {

			connection = MyDbUtils1.getConnection();

			statement = connection.prepareStatement(sql);
			
			//设置参数
			for (int i = 1; i <= args.length; i++) {
				statement.setObject(i, args[i-1]);
			}

			rs = statement.executeQuery();

			// 元数据 Meta 元 （元认知、元学习）
			ResultSetMetaData rsmd = rs.getMetaData();

			// 6.1通过ResultSetMetaData得到columnCount,columnLabel；通过ResultSet得到列值
			int columnCount = rsmd.getColumnCount();

			while (rs.next()) {

				T t = clazz.getDeclaredConstructor().newInstance();
				for (int i = 0; i < columnCount; i++) {
					// 获取列的别名: 列的别名，使⽤类的属性名充当
					String columnLabel = rsmd.getColumnLabel(i + 1);

					// 列值
					Object columnValue = rs.getObject(columnLabel);

					// 使用反射，给对象的相应属性赋值
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columnValue);
				}

				result.add(t);

			}

		} catch (Exception e) {
			// TODO: handle exception
		} finally {
			MyDbUtils1.close(rs, statement, connection);
		}

		return result;

	}

	/**
	 * 查询一个
	 * @param <T> 声明 T是个泛型类型
	 * @param clazz T.class
	 * @param sql sql语句
	 * @param args 参数
	 * @return null or T
	 */
	public static <T> T excuteQueryForOne(Class<T> clazz, String sql, Object... args) {

		Connection connection = null;
		PreparedStatement statement = null;
		ResultSet rs = null;

		try {

			connection = MyDbUtils1.getConnection();

			statement = connection.prepareStatement(sql);
			
			//设置参数
			for (int i = 1; i <= args.length; i++) {
				statement.setObject(i, args[i-1]);
			}

			rs = statement.executeQuery();

			// 元数据 Meta 元 （元认知、元学习）
			ResultSetMetaData rsmd = rs.getMetaData();

			// 6.1通过ResultSetMetaData得到columnCount,columnLabel；通过ResultSet得到列值
			int columnCount = rsmd.getColumnCount();

			if (rs.next()) {

				T t = clazz.getDeclaredConstructor().newInstance();
				for (int i = 0; i < columnCount; i++) {
					// 获取列的别名: 列的别名，使⽤类的属性名充当
					String columnLabel = rsmd.getColumnLabel(i + 1);

					// 列值
					Object columnValue = rs.getObject(columnLabel);

					// 使用反射，给对象的相应属性赋值
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columnValue);
				}

				return t;

			}

		} catch (Exception e) {
			// TODO: handle exception
		} finally {
			MyDbUtils1.close(rs, statement, connection);
		}

		return null;

	}
	
	/**
	 * 封装修改查出操作
	 * @param sql sql语句
	 * @param args 参数
	 * @return
	 */
	public static int excuteUpdate(String sql, Object... args) {
		
		Connection connection = null;
		PreparedStatement statement = null;

		try {

			connection = MyDbUtils1.getConnection();

			statement = connection.prepareStatement(sql);
			
			//设置参数
			for (int i = 1; i <= args.length; i++) {
				statement.setObject(i, args[i-1]);
			}

			return statement.executeUpdate();

		} catch (Exception e) {
			// TODO: handle exception
		} finally {
			MyDbUtils1.close(statement, connection);
		}
		return 0;
	}

}
